﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web;

namespace Nonocast.Http {
	internal class ActionServiceChannel : ServiceChannelBase {
		public ActionServiceChannel(ServiceRequestHeader header, SmallHTTPService host) : base(header, host) { }

		public override void Run() {
			var requestAction = header.RequestUri;
			if ("/" == requestAction) { requestAction = "/Action/Default"; }

			var r = new Regex(@"^/Action/([\w0-9]+)(/[\w0-9]*)?(\?.*)?$", RegexOptions.IgnoreCase);
			if (r.IsMatch(requestAction)) {
				var m = r.Match(requestAction);
				string action = m.Groups[1].Value;
				var method = host.GetType().GetMethod(action);

				object[] args = GetParameters(method, m.Groups[2].Value.TrimStart('/'), m.Groups[3].Value);
				var actionResult = method.Invoke(host, args) as ActionResult;
				if (actionResult == null) { actionResult = new EmptyActionResult(); }
				actionResult.ExecuteResult(Stream);
			}
		}

		private object[] GetParameters(System.Reflection.MethodInfo method, string id, string parameterString) {
			object[] result = new object[] { };
			try {
				var arguments = new Arguments(id, parameterString);
				ChannelContext.Current.Arguments = arguments;

				List<object> parameters = new List<object>();
				foreach (var each in method.GetParameters()) {
					try {
						if (each.ParameterType == typeof(Arguments)) {
							parameters.Add(arguments);
						} else {
							if (arguments.ContainsKey(each.Name)) {
								parameters.Add(TypeDescriptor.GetConverter(each.ParameterType).ConvertFrom(arguments[each.Name]));
							} else {
								parameters.Add(null);
							}
						}
					} catch {
						parameters.Add(null);
					}
				}
				result = parameters.ToArray();
			} catch (Exception ex) {
				Console.WriteLine(ex.Message);
			}
			return result;
		}
	}

	public class Arguments : Dictionary<string, object> {
		public string Id { get; private set; }
		public Arguments() { }
		public Arguments(string id, string data) {
			this["raw"] = data;
			this.Id = id;
			this["id"] = id;

			data = data.TrimStart(new char[] { '?' });
			if (!string.IsNullOrEmpty(data)) {
				var args = data.Split(new char[] { '&' });
				foreach (var each in args) {
					var p = each.Split(new char[] { '=' });
					this[p[0].Trim()] = HttpUtility.UrlDecode(p[1].Trim(), Encoding.UTF8);
				}
			}
		}
	}
}
